﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ProgNetComponents.Design.Attributes
{
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Event, AllowMultiple = true)]
    public abstract class DynamicPropertyDependentAttribute : Attribute, IDynamicAttribute
    {
        #region Members
        private string _PropertyName;
        private object[] _MachingValues;
        protected PropertyInfo _PropertyInfo = null;
        protected FieldInfo _FieldInfo = null;
        #endregion

        #region Properties
        public string PropertyName
        {
            get { return _PropertyName; }
        }
        public object[] MachingValues
        {
            get { return _MachingValues; }
        }
        #endregion

        protected DynamicPropertyDependentAttribute(string PropertyName, params object[] values)
        {
            this._PropertyName = PropertyName;
            this._MachingValues = values;
        }

        protected abstract Attribute GetAttribute(bool PropertyValueMatch);

        #region IDynamicArrtibute Members

        public virtual Attribute GetRealAttribute(object target)
        {
            if (_PropertyInfo == null && _FieldInfo == null)
            {
                _PropertyInfo = target.GetType().GetSingleProperty(PropertyName);
                if (_PropertyInfo == null)
                    _FieldInfo = target.GetType().GetSingleField(PropertyName);
            }
            
            object propertyValue = null;
            if (_PropertyInfo != null)
                propertyValue = _PropertyInfo.GetValue(target);
            else if (_FieldInfo != null)
                propertyValue = _FieldInfo.GetValue(target);
            else 
                throw new Exception("There is no property or field named " + PropertyName + " in type " + target.GetType().FullName);

            bool PropertyValueMatch = MachingValues.IsNull() && propertyValue.IsNull();
            if (!PropertyValueMatch && MachingValues != null)
                PropertyValueMatch = MachingValues.Contains(propertyValue);

            return GetAttribute(PropertyValueMatch);
        }

        #endregion
    }
}
